package com.krtech.wecard.module.sys.service.impl;

import cn.dev33.satoken.SaManager;
import cn.dev33.satoken.context.SaHolder;
import cn.dev33.satoken.stp.StpUtil;
import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.util.IdUtil;
import cn.hutool.core.util.RandomUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.crypto.digest.DigestUtil;
import cn.hutool.http.HttpRequest;
import cn.hutool.http.HttpResponse;
import cn.hutool.http.HttpUtil;
import cn.hutool.json.JSONObject;
import cn.hutool.json.JSONUtil;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.krtech.wecard.framework.exception.BusinessException;
import com.krtech.wecard.framework.model.CommRes;
import com.krtech.wecard.framework.utils.LoginUtil;
import com.krtech.wecard.module.pub.dto.ResultState;
import com.krtech.wecard.module.pub.entity.TnNotify;
import com.krtech.wecard.module.pub.service.impl.TnNotifyServiceImpl;
import com.krtech.wecard.module.sys.entity.StatisticalMain;
import com.krtech.wecard.module.sys.entity.SysKeyValue;
import com.krtech.wecard.module.sys.entity.SysUser;
import com.krtech.wecard.module.sys.enums.StatisticalMainEnums;
import com.krtech.wecard.module.sys.enums.SysEnums;
import com.krtech.wecard.module.sys.mapper.SysUserMapper;
import com.krtech.wecard.module.sys.pojo.LoginVo;
import com.krtech.wecard.module.sys.pojo.PublicSignitureVo;
import com.krtech.wecard.module.sys.pojo.WxAuth;
import com.krtech.wecard.module.sys.service.LoginService;
import com.krtech.wecard.module.sys.service.StatisticalMainService;
import com.krtech.wecard.module.sys.service.SysKeyValueService;
import com.krtech.wecard.module.weixin.bean.WxOpenIdManage;
import com.krtech.wecard.module.weixin.service.WxOpenIdManageService;
import com.krtech.wecard.utils.CommonDecUtils;
import com.krtech.wecard.utils.WxBizDecryptUtils;
import com.krtech.wecard.utils.WxUtil;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

@Slf4j
@Service
public class LoginServiceImpl implements LoginService {

    @Autowired
    private SysKeyValueService keyValueService;

    @Autowired
    private SysUserMapper userMapper;

    @Autowired
    private CommonDecUtils commonUtils;

    @Autowired
    private StatisticalMainService statisticalMainService;

    @Autowired
    private WxOpenIdManageService wxOpenIdManageService;

    @Autowired
    private WxUtil wxUtil;

    @Autowired
    private TnNotifyServiceImpl tnNotifyService;

//    @Autowired
//    private WxBizDecryptUtils wxBizDecryptUtils;


    /**
     *
     * @param wxAuth
     * @return
     */
    @Transactional(rollbackFor = Exception.class)
    @Override
    public CommRes wxLogin(WxAuth wxAuth) {
        if (StrUtil.isNotEmpty(wxAuth.getMipOpenId())){
            String openid = wxAuth.getMipOpenId();
            SysUser user = userMapper.selectOne(new QueryWrapper<SysUser>()
                    .eq(SysUser.COL_MIP_OPEN_ID, openid));

            if (user == null ){
                throw new BusinessException("您的账号异常，请联系管理员");

            }else{
                //如果不为null，就返回正常状态，将账号信息返回

                //查询角色，并且set进入
                //通过adminId查询角色

                // 写入session
                StpUtil.login(user.getUserId());


                LoginVo loginVo = new LoginVo();
                loginVo.setSaTokenInfo(StpUtil.getTokenInfo());
                loginVo.setUserInfo(LoginUtil.getUserInfo());
                loginVo.setRoleList(StpUtil.getRoleList());
                loginVo.setPermissionList(StpUtil.getPermissionList());
                loginVo.setOpenId(openid);

                //判断是否有公众号openId
                loginVo.setHasActivationPublic(0);
                if (StrUtil.isNotEmpty(user.getPublicOpenId())){
                    loginVo.setHasActivationPublic(1);
                }

                return CommRes.ok(loginVo);
            }

        }else{
            if (StrUtil.isEmpty(wxAuth.getCode())){
                return CommRes.error("必填参数不能为空");
            }
            //获得appid和secret
            SysKeyValue appId = keyValueService.getOne(new QueryWrapper<SysKeyValue>()
                    .eq(SysKeyValue.COL_SYS_NAME, SysEnums.WX_APPLETS_APPID));
            SysKeyValue secret = keyValueService.getOne(new QueryWrapper<SysKeyValue>()
                    .eq(SysKeyValue.COL_SYS_NAME, SysEnums.WX_APPLETS_SECRET));

            //构造hutool请求
            String url = "https://api.weixin.qq.com/sns/jscode2session?appid="+appId.getSysValue()+
                    "&secret="+secret.getSysValue()+"&js_code="+ wxAuth.getCode() +"&grant_type=authorization_code";

            String resultStr = HttpUtil.get(url);
            JSONObject jsonObject = JSONUtil.parseObj(resultStr);
            Object openidObj = jsonObject.get("openid");

            log.info("当前用户的openid:"+openidObj);
            Object sessionKeyObj = jsonObject.get("session_key");

            if (openidObj == null || sessionKeyObj == null){
                return CommRes.error("登陆失败");
            }
            String openid = String.valueOf(openidObj);
            String sessionKey = String.valueOf(sessionKeyObj);
            //根据openId，校验是否合法
            // 前端通过手机一键注册，通过openId，查询对应账号，如果查询不到，就建立一个
            SysUser user = userMapper.selectOne(new QueryWrapper<SysUser>()
                    .eq(SysUser.COL_MIP_OPEN_ID, openid));

            wxAuth.setSessionKey(sessionKey);

            String phoneNumber = "";
            if (StrUtil.isNotEmpty(wxAuth.getEncryptedData())){
                try {
                    String phoneRes = WxBizDecryptUtils.wxDecrypt(wxAuth.getEncryptedData(), wxAuth.getSessionKey(), wxAuth.getIv());
                    if (!"".equals(phoneRes)){
                        JSONObject phoneObject = JSONUtil.parseObj(phoneRes);
                        phoneNumber = (String) phoneObject.get("phoneNumber");
                    }
                }catch (Exception e){
                    e.printStackTrace();
                }

            }





            if (user == null ){
                if (StrUtil.isEmpty(phoneNumber)){
                    return CommRes.error("401","非用户不能登陆");
                }
                //如果为null，就重新建一个账号，根据电话号码构建,但是拿不到电话号码,考虑使用openId进行构造
                //查询是否包含有这个电话的账号，如果有，就绑定
                SysUser userBindPhone = userMapper.selectOne(new QueryWrapper<SysUser>()
                        .eq(SysUser.COL_PHONE, phoneNumber));
                //todo 考虑默认添加什么权限（角色）
                if (userBindPhone == null){
                    return CommRes.error("401","非用户不能登陆");
                }
                //绑定openId
                userBindPhone.setMipOpenId(openid);
                userMapper.updateById(userBindPhone);

                // 写入session
                StpUtil.login(userBindPhone.getUserId());

                //返回权限map
                LoginVo loginVo = new LoginVo();
                loginVo.setSaTokenInfo(StpUtil.getTokenInfo());

                loginVo.setUserInfo(userBindPhone);

                loginVo.setRoleList(StpUtil.getRoleList());
                loginVo.setPermissionList(StpUtil.getPermissionList());
                loginVo.setOpenId(openid);

                loginVo.setSessionKey(sessionKey);

                //判断是否有公众号openId
                loginVo.setHasActivationPublic(0);
                if (StrUtil.isNotEmpty(userBindPhone.getPublicOpenId())){
                    loginVo.setHasActivationPublic(1);
                }

                return CommRes.ok(loginVo);

            }else{
                //如果不为null，就返回正常状态，将账号信息返回

                //查询角色，并且set进入
                //通过adminId查询角色

                // 写入session
                StpUtil.login(user.getUserId());


                LoginVo loginVo = new LoginVo();
                loginVo.setSaTokenInfo(StpUtil.getTokenInfo());

                loginVo.setUserInfo(user);

                loginVo.setRoleList(StpUtil.getRoleList());
                loginVo.setPermissionList(StpUtil.getPermissionList());
                loginVo.setOpenId(openid);
                loginVo.setSessionKey(sessionKey);

                //判断是否有公众号openId
                loginVo.setHasActivationPublic(0);
                if (StrUtil.isNotEmpty(user.getPublicOpenId())){
                    loginVo.setHasActivationPublic(1);
                }

                return CommRes.ok(loginVo);
            }
        }
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public String wxAdminLogin(String code, String phone) {
        if (StrUtil.isEmpty(code)){
            throw new BusinessException("必填参数不能为空");
        }
        //获得appid和secret
        SysKeyValue appId = keyValueService.getOne(new QueryWrapper<SysKeyValue>()
                .eq(SysKeyValue.COL_SYS_NAME, SysEnums.WX_PUBLIC_APPID));
        SysKeyValue secret = keyValueService.getOne(new QueryWrapper<SysKeyValue>()
                .eq(SysKeyValue.COL_SYS_NAME, SysEnums.WX_PUBLIC_SECRET));

        //构造hutool请求
//        String url = "https://api.weixin.qq.com/sns/jscode2session?appid="+appId+
//                "&secret="+secret+"&js_code="+ code +"&grant_type=authorization_code";

        String url = "https://api.weixin.qq.com/sns/oauth2/access_token?appid="+appId.getSysValue()+
                "&secret="+secret.getSysValue()+"&code="+code+"&grant_type=authorization_code";

        String resultStr = HttpUtil.get(url);
        JSONObject jsonObject = JSONUtil.parseObj(resultStr);
        Object openidObj = jsonObject.get("openid");
        log.info("当前用户的openid:"+openidObj);

        Object sessionKeyObj = jsonObject.get("session_key");

        if (openidObj == null){
            throw new BusinessException("微信登陆失败");

        }
        String openid = String.valueOf(openidObj);
        String sessionKey = String.valueOf(sessionKeyObj);

        //根据openId，校验是否合法
        // 前端通过手机一键注册，通过openId，查询对应账号，如果查询不到，就建立一个
        SysUser user = userMapper.selectOne(new QueryWrapper<SysUser>()
                .eq(SysUser.COL_OPEN_ID_ADMIN, openid));

        SysKeyValue redirectUrl = keyValueService.getOne(new QueryWrapper<SysKeyValue>()
                .eq(SysKeyValue.COL_SYS_NAME, SysEnums.WX_LOGIN_URL));

        if (redirectUrl == null){
            throw new BusinessException("没有重定向地址");
//            return "没有重定向地址";
        }

        if (user == null){
            //如果为null，就重新建一个账号，根据电话号码构建,但是拿不到电话号码,考虑使用openId进行构造
            //查询是否包含有这个电话的账号，如果有，就绑定
            //正常来说回调是不会带有phone的，不会建号
            if (StrUtil.isEmpty(phone)){
                throw new BusinessException("您不能登陆");
//                return "您不能登陆";
            }

            SysUser userBindPhone = userMapper.selectOne(new QueryWrapper<SysUser>()
                    .eq(SysUser.COL_PHONE, phone));
            //todo 考虑默认添加什么权限（角色）
            if (userBindPhone == null){
                throw new BusinessException("非用户不能登陆");
//                return "非用户不能登陆";
            }
            //绑定openId
            userBindPhone.setOpenIdAdmin(openid);
            userMapper.updateById(userBindPhone);

            // 写入session
            StpUtil.login(userBindPhone.getUserId());

            LoginVo loginVo = new LoginVo();
            loginVo.setSaTokenInfo(StpUtil.getTokenInfo());
            loginVo.setUserInfo(LoginUtil.getUserInfo());
            loginVo.setRoleList(StpUtil.getRoleList());
            loginVo.setPermissionList(StpUtil.getPermissionList());
            loginVo.setOpenId(openid);


            SysKeyValue WxBindUrl = keyValueService.getOne(new QueryWrapper<SysKeyValue>()
                    .eq(SysKeyValue.COL_SYS_NAME, SysEnums.WX_BIND_URL));

            String redirectUrlStr = "redirect:"+WxBindUrl.getSysValue() + "?";

            Map<String, Object> params = new HashMap<>();
            params.put("id",userBindPhone.getUserId());
            String toParams = HttpUtil.toParams(params);

            redirectUrlStr = redirectUrlStr + toParams;

            return redirectUrlStr;


        }else{
            //如果不为null，就返回正常状态，将账号信息返回


            // 写入session

            StpUtil.login(user.getUserId());

            List<String> roleList = StpUtil.getRoleList();
            List<String> permissionList = StpUtil.getPermissionList();

            //判断这个人 是否拥有超级管理员权限，在keyvalue中查询超级管理员的id
            boolean judgeAdmin = LoginUtil.judgeAdmin();

            if (!judgeAdmin){
                throw new BusinessException("您不是超级管理员，不能登陆管理平台");
            }


            String redirectUrlStr = "redirect:"+redirectUrl.getSysValue() + "?";

            Map<String, Object> params = new HashMap<>();
            params.put("wecard",StpUtil.getTokenValue());
            String toParams = HttpUtil.toParams(params);

            redirectUrlStr = redirectUrlStr + toParams;

            return redirectUrlStr;
        }
    }



    @Transactional(rollbackFor = Exception.class)
    @Override
    public String wxPublicLogin(String code, String phone) {
        if (StrUtil.isEmpty(code)){
            throw new BusinessException("必填参数不能为空");
        }
        //获得appid和secret
        SysKeyValue appId = keyValueService.getOne(new QueryWrapper<SysKeyValue>()
                .eq(SysKeyValue.COL_SYS_NAME, SysEnums.WX_PUBLIC_NUMBER_APPID));
        SysKeyValue secret = keyValueService.getOne(new QueryWrapper<SysKeyValue>()
                .eq(SysKeyValue.COL_SYS_NAME, SysEnums.WX_PUBLIC_NUMBER_SECRET));

        //构造hutool请求
//        String url = "https://api.weixin.qq.com/sns/jscode2session?appid="+appId+
//                "&secret="+secret+"&js_code="+ code +"&grant_type=authorization_code";

        String url = "https://api.weixin.qq.com/sns/oauth2/access_token?appid="+appId.getSysValue()+
                "&secret="+secret.getSysValue()+"&code="+code+"&grant_type=authorization_code";

        String resultStr = HttpUtil.get(url);
        JSONObject jsonObject = JSONUtil.parseObj(resultStr);
        Object openidObj = jsonObject.get("openid");
        log.info("当前用户的openid:"+openidObj);

        Object sessionKeyObj = jsonObject.get("session_key");

        if (openidObj == null){
            throw new BusinessException("微信登陆失败");

        }
        String openid = String.valueOf(openidObj);
        String sessionKey = String.valueOf(sessionKeyObj);

        //根据openId，校验是否合法
        // 前端通过手机一键注册，通过openId，查询对应账号，如果查询不到，就建立一个
        SysUser user = userMapper.selectOne(new QueryWrapper<SysUser>()
                .eq(SysUser.COL_PUBLIC_OPEN_ID, openid));

        SysKeyValue redirectUrl = keyValueService.getOne(new QueryWrapper<SysKeyValue>()
                .eq(SysKeyValue.COL_SYS_NAME, SysEnums.WX_PUBLIC_NUMBER_REDIRECT_URL));

        if (redirectUrl == null){
            throw new BusinessException("没有重定向地址");
        }

        if (user == null){
            //如果为null，就重新建一个账号，根据电话号码构建,但是拿不到电话号码,考虑使用openId进行构造
            //查询是否包含有这个电话的账号，如果有，就绑定
            //正常来说回调是不会带有phone的，不会建号
            if (StrUtil.isEmpty(phone)){
                throw new BusinessException("您不能登陆");
            }

            SysUser userBindPhone = userMapper.selectOne(new QueryWrapper<SysUser>()
                    .eq(SysUser.COL_PHONE, phone));
            //todo 考虑默认添加什么权限（角色）
            if (userBindPhone == null){
                throw new BusinessException("非用户不能登陆");
            }
            //绑定openId
            userBindPhone.setPublicOpenId(openid);
            userMapper.updateById(userBindPhone);

            // 写入session
            StpUtil.login(userBindPhone.getUserId());

            LoginVo loginVo = new LoginVo();
            loginVo.setSaTokenInfo(StpUtil.getTokenInfo());
            loginVo.setUserInfo(LoginUtil.getUserInfo());
            loginVo.setRoleList(StpUtil.getRoleList());
            loginVo.setPermissionList(StpUtil.getPermissionList());
            loginVo.setOpenId(openid);



            String redirectUrlStr = "redirect:"+redirectUrl.getSysValue() + "?";

            Map<String, Object> params = new HashMap<>();
            params.put("id",userBindPhone.getUserId());
            String toParams = HttpUtil.toParams(params);

            redirectUrlStr = redirectUrlStr + toParams;

            return redirectUrlStr;


        }else{
            //如果不为null，就返回正常状态，将账号信息返回
            // 写入session

            StpUtil.login(user.getUserId());


            String redirectUrlStr = "redirect:"+redirectUrl.getSysValue() + "?";

            Map<String, Object> params = new HashMap<>();
            params.put("id",user.getUserId());
            String toParams = HttpUtil.toParams(params);

            redirectUrlStr = redirectUrlStr + toParams;

            return redirectUrlStr;
        }
    }

    @Override
    public String wxPublicJudgeFocus(String code, String phone) {
        if (StrUtil.isEmpty(code)){
            throw new BusinessException("必填参数不能为空");
        }
        //获得appid和secret
        SysKeyValue appId = keyValueService.getOne(new QueryWrapper<SysKeyValue>()
                .eq(SysKeyValue.COL_SYS_NAME, SysEnums.WX_PUBLIC_NUMBER_APPID));
        SysKeyValue secret = keyValueService.getOne(new QueryWrapper<SysKeyValue>()
                .eq(SysKeyValue.COL_SYS_NAME, SysEnums.WX_PUBLIC_NUMBER_SECRET));

        //构造hutool请求
        String url = "https://api.weixin.qq.com/sns/oauth2/access_token?appid="+appId.getSysValue()+
                "&secret="+secret.getSysValue()+"&code="+code+"&grant_type=authorization_code";

        String resultStr = HttpUtil.get(url);
        JSONObject jsonObject = JSONUtil.parseObj(resultStr);
        Object openidObj = jsonObject.get("openid");
        log.info("当前用户的openid:"+openidObj);


        if (openidObj == null){
            throw new BusinessException("微信登陆失败");

        }
        String openid = String.valueOf(openidObj);

        WxOpenIdManage wxOpenIdManage = this.getOpenIdManageInfoByPublicOpenId(openid);

        SysKeyValue redirectUrl = keyValueService.getOne(new QueryWrapper<SysKeyValue>()
                .eq(SysKeyValue.COL_SYS_NAME, SysEnums.WX_PUBLIC_NUMBER_REDIRECT_URL));

        if (redirectUrl == null){
            throw new BusinessException("没有重定向地址");
        }
        // 电话不为空，顺便进行绑定
        SysUser user = userMapper.selectOne(new QueryWrapper<SysUser>().eq(SysUser.COL_DEL_FLAG, 0).eq(SysUser.COL_PHONE, phone));
        if (user != null){
            user.setPublicOpenId(openid);
            user.setHasFocusPublicNumber(wxOpenIdManage.getHasFocusPublicNumber());

            userMapper.updateById(user);
        }

        //todo 发消息验证是否关注了公众号
        if (wxOpenIdManage.getHasFocusPublicNumber() == 0){
            boolean sendMsgJudgeFocus = sendMsgJudgeFocus(openid,user);
            if (sendMsgJudgeFocus){
                wxOpenIdManage.setHasFocusPublicNumber(1);
                wxOpenIdManageService.updateById(wxOpenIdManage);

                //改变父级绑定情况
                if (user != null){
                    user.setHasFocusPublicNumber(wxOpenIdManage.getHasFocusPublicNumber());

                    userMapper.updateById(user);
                }
            }
        }



        String redirectUrlStr = "redirect:"+redirectUrl.getSysValue() + "?";

        Map<String, Object> params = new HashMap<>();
        params.put("hasFocusPublicNumber",wxOpenIdManage.getHasFocusPublicNumber());

        String toParams = HttpUtil.toParams(params);

        redirectUrlStr = redirectUrlStr + toParams;

        return redirectUrlStr;
    }

    @Override
    public String wxPublicGetWecard(String code, String phone) {
        if (StrUtil.isEmpty(code)){
            throw new BusinessException("必填参数不能为空");
        }
        //获得appid和secret
        SysKeyValue appId = keyValueService.getOne(new QueryWrapper<SysKeyValue>()
                .eq(SysKeyValue.COL_SYS_NAME, SysEnums.WX_PUBLIC_NUMBER_APPID));
        SysKeyValue secret = keyValueService.getOne(new QueryWrapper<SysKeyValue>()
                .eq(SysKeyValue.COL_SYS_NAME, SysEnums.WX_PUBLIC_NUMBER_SECRET));

        //构造hutool请求
        String url = "https://api.weixin.qq.com/sns/oauth2/access_token?appid="+appId.getSysValue()+
                "&secret="+secret.getSysValue()+"&code="+code+"&grant_type=authorization_code";

        String resultStr = HttpUtil.get(url);
        JSONObject jsonObject = JSONUtil.parseObj(resultStr);
        Object openidObj = jsonObject.get("openid");
        log.info("当前用户的openid:"+openidObj);


        if (openidObj == null){
            throw new BusinessException("微信登陆失败");

        }
        String openid = String.valueOf(openidObj);

        SysKeyValue redirectUrl = keyValueService.getOne(new QueryWrapper<SysKeyValue>()
                .eq(SysKeyValue.COL_SYS_NAME, SysEnums.MIP_CARRY_TOKEN_URL));

        if (redirectUrl == null){
            throw new BusinessException("没有重定向地址");
        }

        String redirectUrlStr = "redirect:"+redirectUrl.getSysValue() + "?";

        Map<String, Object> params = new HashMap<>();

        //根据openId查询用户
        SysUser userFromOpenId = userMapper.selectOne(new QueryWrapper<SysUser>().eq(SysUser.COL_DEL_FLAG, 0)
                .eq(SysUser.COL_PUBLIC_OPEN_ID, openid));

        if (userFromOpenId == null){
//            throw new BusinessException("您的账号未完成公众号绑定，请完成公众号绑定");
            throw new BusinessException("该账号未存在于\"手机微卡平台\"，请先注册并登录\"手机微卡\"后，再访问");
        }

        StpUtil.login(userFromOpenId.getUserId());
        String tokenValue = StpUtil.getTokenInfo().getTokenValue();
        params.put("wecard",tokenValue);

        String toParams = HttpUtil.toParams(params);

        redirectUrlStr = redirectUrlStr + toParams;

        return redirectUrlStr;
    }

    public boolean sendMsgJudgeFocus(String openid,SysUser user){
        TnNotify tnNotify = new TnNotify();
        tnNotify.setNotifyTitle("欢迎登陆微卡");
        if (user != null){
            tnNotify.setNotifySenderUserName(user.getNickName());
        }
        tnNotify.setNotifyContent("欢迎登陆微卡");
        tnNotify.setNotifyCreatedTime(new Date());

        SysKeyValue moduleId = keyValueService.getOne(new QueryWrapper<SysKeyValue>()
                .eq(SysKeyValue.COL_SYS_NAME, SysEnums.PUBLIC_NOTIFY_FOCUS_PRE_MODULE_ID));

        ResultState resultState = tnNotifyService.noticeTemplateFocusPre(tnNotify, openid,moduleId.getSysValue());
        if (resultState.getErrcode() == 43004){
            return false;

        }else if (resultState.getErrcode() == 0){
            return true;
        }else {
            return false;
        }
    }


    /**
     * 直接获得用户信息，必须得得到用户 授权，此方法不考虑
     *
     * @param token
     * @param openid
     * @return
     */
    public  boolean userIsFollowPublic(String token,String openid){
        Integer subscribe = 0;
        String url = "https://api.weixin.qq.com/cgi-bin/user/info?access_token="+token+"&openid="+openid+"&lang=zh_CN";
        try {
            HttpRequest get = HttpUtil.createGet(url);
            HttpResponse execute = get.execute();
            String body = execute.body();

            JSONObject jsonObject = JSONUtil.parseObj(body);
            System.out.println(jsonObject);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return 1 == subscribe;
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public String wxPublicMessageLogin(String code, String phone) {
        if (StrUtil.isEmpty(code)){
            throw new BusinessException("必填参数不能为空");
        }
        //获得appid和secret
        SysKeyValue appId = keyValueService.getOne(new QueryWrapper<SysKeyValue>()
                .eq(SysKeyValue.COL_SYS_NAME, SysEnums.WX_PUBLIC_NUMBER_APPID));
        SysKeyValue secret = keyValueService.getOne(new QueryWrapper<SysKeyValue>()
                .eq(SysKeyValue.COL_SYS_NAME, SysEnums.WX_PUBLIC_NUMBER_SECRET));

        //构造hutool请求
//        String url = "https://api.weixin.qq.com/sns/jscode2session?appid="+appId+
//                "&secret="+secret+"&js_code="+ code +"&grant_type=authorization_code";

        String url = "https://api.weixin.qq.com/sns/oauth2/access_token?appid="+appId.getSysValue()+
                "&secret="+secret.getSysValue()+"&code="+code+"&grant_type=authorization_code";

        String resultStr = HttpUtil.get(url);
        JSONObject jsonObject = JSONUtil.parseObj(resultStr);
        Object openidObj = jsonObject.get("openid");
        log.info("当前用户的openid:"+openidObj);

        Object sessionKeyObj = jsonObject.get("session_key");

        if (openidObj == null){
            throw new BusinessException("微信登陆失败");

        }
        String openid = String.valueOf(openidObj);
        String sessionKey = String.valueOf(sessionKeyObj);

        //根据openId，校验是否合法
        // 前端通过手机一键注册，通过openId，查询对应账号，如果查询不到，就建立一个
        SysUser user = userMapper.selectOne(new QueryWrapper<SysUser>()
                .eq(SysUser.COL_PUBLIC_OPEN_ID, openid));

        SysKeyValue redirectUrl = keyValueService.getOne(new QueryWrapper<SysKeyValue>()
                .eq(SysKeyValue.COL_SYS_NAME, SysEnums.WX_PUBLIC_NUMBER_TARGET_URL));

        if (redirectUrl == null){
            throw new BusinessException("没有重定向地址");
        }

        if (user == null){
            //如果为null，就重新建一个账号，根据电话号码构建,但是拿不到电话号码,考虑使用openId进行构造
            //查询是否包含有这个电话的账号，如果有，就绑定
            //正常来说回调是不会带有phone的，不会建号
            if (StrUtil.isEmpty(phone)){
                throw new BusinessException("您不能登陆");
            }

            SysUser userBindPhone = userMapper.selectOne(new QueryWrapper<SysUser>()
                    .eq(SysUser.COL_PHONE, phone));
            //todo 考虑默认添加什么权限（角色）
            if (userBindPhone == null){
                throw new BusinessException("非用户不能登陆");
            }
            //绑定openId
            userBindPhone.setPublicOpenId(openid);
            userMapper.updateById(userBindPhone);

            // 写入session
            StpUtil.login(userBindPhone.getUserId());

            LoginVo loginVo = new LoginVo();
            loginVo.setSaTokenInfo(StpUtil.getTokenInfo());
            loginVo.setUserInfo(LoginUtil.getUserInfo());
            loginVo.setRoleList(StpUtil.getRoleList());
            loginVo.setPermissionList(StpUtil.getPermissionList());
            loginVo.setOpenId(openid);



            String redirectUrlStr = "redirect:"+redirectUrl.getSysValue() + "?";

            Map<String, Object> params = new HashMap<>();
            params.put("id",userBindPhone.getUserId());
            String toParams = HttpUtil.toParams(params);

            redirectUrlStr = redirectUrlStr + toParams;

            return redirectUrlStr;


        }else{
            //如果不为null，就返回正常状态，将账号信息返回
            // 写入session

            StpUtil.login(user.getUserId());


            String redirectUrlStr = "redirect:"+redirectUrl.getSysValue() + "?";

            Map<String, Object> params = new HashMap<>();
            params.put("id",user.getUserId());
            String toParams = HttpUtil.toParams(params);

            redirectUrlStr = redirectUrlStr + toParams;

            return redirectUrlStr;
        }
    }

    @Override
    public PublicSignitureVo getPubliSigniture() {
        //获得页面地址
        SysKeyValue url = keyValueService.getOne(new QueryWrapper<SysKeyValue>()
                .eq(SysKeyValue.COL_SYS_NAME, SysEnums.WX_PUBLIC_NUMBER_REDIRECT_URL));

        //去redis拿 jsapi_ticket
        String jsapiTicket = getJsapiTicket();

        //生成签名
        PublicSignitureVo publicSignitureVo = new PublicSignitureVo();
        publicSignitureVo.setNoncestr(IdUtil.simpleUUID());
        publicSignitureVo.setUrl(url.getSysValue());
        publicSignitureVo.setTimestamp(System.currentTimeMillis());
        publicSignitureVo.setJsapi_ticket(jsapiTicket);

        PublicSignitureVo sign = sign(publicSignitureVo);
        return sign;
    }

    @Override
    public WxOpenIdManage getOpenIdManageInfoByPublicOpenId(String publicOpenId) {
        WxOpenIdManage wxOpenIdManage = wxOpenIdManageService.getOne(new QueryWrapper<WxOpenIdManage>()
                .eq(WxOpenIdManage.COL_PUBLIC_OPEN_ID, publicOpenId));

        if (wxOpenIdManage != null){
            return wxOpenIdManage;
        }else {
            WxOpenIdManage newWxOpenIdManage = new WxOpenIdManage();
            newWxOpenIdManage.setPublicOpenId(publicOpenId);
            newWxOpenIdManage.setHasFocusPublicNumber(0);
            newWxOpenIdManage.setCreatedTime(new Date());
            wxOpenIdManageService.save(newWxOpenIdManage);
            wxOpenIdManage = newWxOpenIdManage;
        }

        return wxOpenIdManage;
    }

    public void getPhone(String code){
        String publicAccessToken = getPublicAccessToken();

        //构造hutool请求
        String url = "https://api.weixin.qq.com/wxa/business/getuserphonenumber?access_token="+publicAccessToken;

        String resultStr = HttpUtil.get(url);
        JSONObject jsonObject = JSONUtil.parseObj(resultStr);
        log.info("phoone:"+jsonObject);
    }

    public String getJsapiTicket(){
        String jsapiTicket = SaManager.getSaTokenDao().get("jsapi_ticket");
        if (StrUtil.isEmpty(jsapiTicket)){
            String publicAccessToken = getPublicAccessToken();

            //构造hutool请求
            String url = "https://api.weixin.qq.com/cgi-bin/ticket/getticket?access_token="+publicAccessToken+"&type=jsapi";

            String resultStr = HttpUtil.get(url);
            JSONObject jsonObject = JSONUtil.parseObj(resultStr);
            Object access_token = jsonObject.get("errmsg");
            if (access_token != null && "ok".equals(String.valueOf(access_token))){
                Object ticket = jsonObject.get("ticket");
                Object expires_in = jsonObject.get("expires_in");

                SaManager.getSaTokenDao().set("jsapi_ticket",String.valueOf(ticket),Long.parseLong(String.valueOf(expires_in)));
            }else {
                throw new BusinessException("获得jsapi_ticket异常");
            }
        }

        return SaManager.getSaTokenDao().get("jsapi_ticket");
    }

    public String getPublicAccessToken(){
        String publicAccessToken = SaManager.getSaTokenDao().get("public_access_token");
        if (StrUtil.isNotEmpty(publicAccessToken)){
            return publicAccessToken;
        }else if (StrUtil.isEmpty(publicAccessToken)){
            // 新生成access_token
            //获得appid和secret
            SysKeyValue appId = keyValueService.getOne(new QueryWrapper<SysKeyValue>()
                    .eq(SysKeyValue.COL_SYS_NAME, SysEnums.WX_PUBLIC_NUMBER_APPID));
            SysKeyValue secret = keyValueService.getOne(new QueryWrapper<SysKeyValue>()
                    .eq(SysKeyValue.COL_SYS_NAME, SysEnums.WX_PUBLIC_NUMBER_SECRET));

            SysKeyValue refreshTime = keyValueService.getOne(new QueryWrapper<SysKeyValue>()
                    .eq(SysKeyValue.COL_SYS_NAME, SysEnums.REFRESH_TIME));

            //构造hutool请求
            String url = "https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid="+appId.getSysValue()+"&secret="+secret.getSysValue();

            log.info("获得公众号accessToken的url:"+url);
            String resultStr = HttpUtil.get(url);
            log.info("获得公众号accessToken的返回值:"+resultStr);
            JSONObject jsonObject = JSONUtil.parseObj(resultStr);
            Object access_token = jsonObject.get("access_token");
            Object access_token_time = jsonObject.get("expires_in");

            if (access_token == null){
                throw new BusinessException("获得publicAccessToken异常");
            }

            SaManager.getSaTokenDao().set("public_access_token",String.valueOf(access_token),Long.parseLong(String.valueOf(refreshTime.getSysValue())));
        }

        //确定有了
        return SaManager.getSaTokenDao().get("public_access_token");
    }

    public void deletePublicAccessToken(){
        SaManager.getSaTokenDao().delete("public_access_token");
    }

    public PublicSignitureVo sign(PublicSignitureVo publicSignitureVo){
        Map<String, Object> map = BeanUtil.beanToMap(publicSignitureVo);

        List<String> keySortList = map.keySet().stream().sorted().collect(Collectors.toList());



        String signStr = "";
        for (String keySort:keySortList){
            Object obj = map.get(keySort);
            if (obj != null && obj != ""){
                signStr = signStr + keySort + "=" + obj + "&";
            }
        }


        String sign = DigestUtil.md5Hex(signStr);

        publicSignitureVo.setSign(sign);
        return publicSignitureVo;
    }


}
